<?php

namespace App\Repository;

use App\Repository\Criteria;
use Illuminate\Support\Collection;
use App\Repository\EagerLoading;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Container\Container as App;
use App\Repository\CriteriaRepository;
use App\Repository\Exceptions\RepositoryException;
use App\Repository\Constracts\RepositoryInterface;
use App\Repository\Constracts\TransformerInterface;

abstract class BaseRepository extends CriteriaRepository implements RepositoryInterface, TransformerInterface
{
    use EagerLoading, Transformer;

    /**
     * @var App
     */
    private $app;

    /**
     * @var
     */
    protected $model;

    /**
     * @param App $app
     * @throws Repositories\Exceptions\RepositoryException
     */
    public function __construct(App $app, Collection $collection)
    {
        $this->app      = $app;
        $this->criteria = $collection;
        $this->resetScope();
        $this->makeModel();
    }

    /**
     * Specify Model class name
     *
     * @return mixed
     */
    public abstract function model();

    /**
     * @return Model
     * @throws RepositoryException
     */
    public function makeModel()
    {
        $model = $this->app->make($this->model());

        if (!$model instanceof Model) {
            throw new RepositoryException("Class {$this->model()} must be an instance of Illuminate\\Database\\Eloquent\\Model");
        }

        return $this->model = $model->newQuery();
    }

    public function all($columns = array('*'))
    {
        $this->applyCriteria();
        $this->newQuery()->eagerLoadRelations();
        return $this->transformCollection($this->model->get($columns));
    }

    public function get($columns = array('*'))
    {
        $this->applyCriteria();
        $this->newQuery()->eagerLoadRelations();
        return $this->transformCollection($this->model->get($columns));
    }

    public function first($columns = array('*'))
    {
        $this->applyCriteria();
        $this->newQuery()->eagerLoadRelations();
        return $this->transformCollection($this->model->first($columns));
    }

    public function paginate($perPage = 15, $columns = array('*'))
    {
        $this->applyCriteria();
        $this->newQuery()->eagerLoadRelations();
        $data = $this->model->paginate($perPage, $columns);
        $this->transformCollection($data->items());
        return $data;
    }

    public function create(array $data)
    {
        if (isset($data['id'])) unset($data['id']);

        return $this->model->create($data);
    }

    public function update(array $data, $id)
    {
        if (isset($data['id'])) unset($data['id']);
        $this->makeModel();
        $this->resetCriteria();
        return $this->model->find($id)->update($data);
    }

    public function delete($id)
    {
        $this->makeModel();
        $this->resetCriteria();
        $model = $this->model->find($id);
        if ($model == null) {
            return true;
        }

        return $model->delete();
    }

    public function find($id, $columns = array('*'))
    {
        $this->applyCriteria();
        $this->newQuery()->eagerLoadRelations();
        return $this->transformCollection($this->model->find($id, $columns));
    }

    public function findFirstRowByFields(array $fields, $columns = array('*'))
    {
        $this->applyCriteria();
        $this->newQuery()->eagerLoadRelations();
        return $this->transformCollection($this->model->where($fields)->first($columns));
    }


    public function findByFields(array $fields, $columns = array('*'))
    {
        $this->makeModel();
        $this->applyCriteria();
        $this->newQuery()->eagerLoadRelations();
        return $this->transformCollection($this->model->where($fields)->get($columns));
    }


    public function batchDelete()
    {
        $this->applyCriteria();
        return $this->model->delete();
    }

    public  function __call($name, $arguments)
    {
        return call_user_func_array(array(&$this->model, $name), $arguments);
    }
}
